﻿using Nemerle.Collections;
using Nemerle.Text;
using Nemerle.Utility;
using Nemerle.Compiler;
using Nemerle.Compiler.Parsetree;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace NRails.Macros
{
    enum Phase
    {
        | BeforeInheritance
        | BeforeTypedMembers
        | WithTypedMembers
    }
    
    [Nemerle.MacroUsage(Nemerle.MacroPhase.BeforeInheritance, Nemerle.MacroTargets.Assembly)]
    macro NRailsInit(params args : array[expr])
    {
        NRailsInitsImpl.ParseParams(args.ToNList());
        NRailsInitsImpl.Init(Nemerle.Macros.ImplicitCTX(), Nemerle.Macros.Manager(), Phase.BeforeInheritance);
    }
    
    [Nemerle.MacroUsage(Nemerle.MacroPhase.BeforeTypedMembers, Nemerle.MacroTargets.Assembly)]
    macro NRailsInit(params args : array[expr])
    {
       NRailsInitsImpl.Init(Nemerle.Macros.ImplicitCTX(), Nemerle.Macros.Manager(), Phase.BeforeTypedMembers);
    }
    
    [Nemerle.MacroUsage(Nemerle.MacroPhase.WithTypedMembers, Nemerle.MacroTargets.Assembly)]
    macro NRailsInit(params args : array[expr])
    {
       NRailsInitsImpl.Init(Nemerle.Macros.ImplicitCTX(), Nemerle.Macros.Manager(), Phase.WithTypedMembers);
    }
    
    module NRailsInitsImpl
    {
        public IncludeTables : string { get; private set; }
        public ExcludeTables : string { get; private set; }
        public GenerateMissingModelsFromDbSchema : bool { get; private set; }

        this()
        {
            IncludeTables = ".*";
            ExcludeTables = "sysdiagrams";
            GenerateMissingModelsFromDbSchema = true;
        }

        public FilterTable(tableName : string) : bool
        {
            def includeRgx = Regex(NRailsInitsImpl.IncludeTables);
            def excludeRgx = Regex(NRailsInitsImpl.ExcludeTables);
            includeRgx.IsMatch(tableName) && !excludeRgx.IsMatch(tableName)
        }
        
        public ParseParams(args : list[PExpr]) : void
        {
            | PExpr.Assign(PExpr.Ref(key), PExpr.Literal(Literal.String(value))) :: tail =>
                match (key.Id)
                {
                    | "Include" => IncludeTables = value;
                    | "Exclude" => ExcludeTables = value;
                    | _ => ()
                }
                ParseParams(tail);
            | PExpr.Assign(PExpr.Ref(key), PExpr.Literal(Literal.Bool(value))) :: tail =>
                match (key.Id)
                {
                    | "GenerateMissingModelsFromDbSchema" => GenerateMissingModelsFromDbSchema = value;
                    | _ => ()
                }
                ParseParams(tail);
            | _ => ()
        }
        
        public Init(ctx : Typer, manager: ManagerClass, phase : Phase) : void
        {
           InitConstants.Init(ctx, manager, phase);
        }
    }
}
